
#include "client.h"
#include <cerrno>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <unistd.h>
#include "define.h"
#include "tools_util.h"
#include "./../../log_module/log_module_define.h"

Client::Client(Loop * loop)
{
    m_loop = loop;
}

Client::~Client()
{
    TRACE("free client");
}

void Client::MessageCallbackFunc(ClientMessage && func)
{
    m_message = func;
}

void Client::ErrorCallbackFunc(ClientError && func)
{
    m_error = func;
}

void Client::ConnectCallbackFunc(ClientConnect && func)
{
    m_connect = func;
}

bool Client::Connect(const std::string & url, ClientConfig config)
{
    UrlInfo info;
    auto result = GetServerAddrInfo(url, info);
    if (!result)
    {
        return false;
    }
    return Connection(info, config);
}
bool Client::Connect(const std::string & ip, uint16_t port, ClientConfig config)
{
    UrlInfo info;
    info.domain = ip;
    info.protocol = std::to_string(port);
    GetAddrInfo(info);
    return Connection(info, config);
}

bool Client::Connection(UrlInfo & info, ClientConfig & config)
{
    m_socket = std::make_shared<TcpSocket>();
    for (auto & data : info.server_vec)
    {
        m_socket->CreateSocket();
        bool result = m_socket->Connect(data.ip, data.port);
        if (result)
        {
            m_socket_buffer = std::make_shared<SocketBuffer>(m_socket);
            m_channel       = std::make_shared<Channel>(m_loop,m_socket); 
            m_channel->ReadFuncCallback(std::bind(&Client::Message, this, std::placeholders::_1, std::placeholders::_2));
            m_channel->ErrFuncCallback(std::bind(&Client::Error, this, std::placeholders::_1, std::placeholders::
                        _2));
            if (!config.socket_block)
            {
                m_socket->NonBlack();
            }
            if (m_connect)
            {
                m_connect(m_socket_buffer);
            }
            m_channel->AddEvent(EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
            return true;
        }
    }
    return false;
}

void Client::Message(std::shared_ptr<Channel> channel, std::shared_ptr<TcpSocket> socket)
{
    TRACE("recv message from server");
    int result = m_socket_buffer->ReadData();
    if (result < 0)
    {
        if (m_socket_buffer->GetBufferLength() > 0 && m_message)
        {        
            m_message(m_socket_buffer);
        }
        if (m_error)
        {
            m_error(std::to_string(-1));
        }
        m_channel->DelEvent();
    }
    else
    {
        if (m_message) 
        {
            m_message(m_socket_buffer);
        }
        m_channel->ModEvent(EmIoIn | EmIoErr | EmIoRdHup | EmIoOneShot);
    }
}

void Client::Error(std::shared_ptr<Channel> channel, std::shared_ptr<TcpSocket> socket)
{
    TRACE("error happen on client connection");
    if (m_message && m_socket_buffer->GetBufferLength() > 0)
    {
        m_message(m_socket_buffer);
    }
    if (m_error)
    {
        m_error(std::to_string(-1));
    }
    m_channel->DelEvent();
}

void Client::Close()
{
    m_channel->DelEvent();
    m_socket->Close();
    auto self = shared_from_this();
    m_loop->AddPendingTask([self](){
            
        if (self->m_error)      
        {
            self->m_error(std::to_string(-2));
        }
    });
}

int Client::SendData(const uint8_t * data, int length)
{
    return write(m_socket->GetSocket(), data, length);
}
